package models;

import java.io.Serializable;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import lib.Field;
import lib.Observer;
import lib.Subject;
import lib.persistence.NotFoundException;
import lib.persistence.commands.DeleteRow;
import lib.persistence.commands.GetRow;
import lib.persistence.commands.InsertRow;
import lib.persistence.commands.UpdateRow;

public abstract class ModelAbstract implements Subject, ICreateUpdateDelete,Serializable
{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1245180301976162653L;
	protected int id = -1;
	
	/**
	 * returns a set of Field objects that are used to pair column names with values for SQL queries
	 * @return
	 */
	protected abstract ArrayList<Field> getSqlReadyFields();
	/**
	 * Each model loosely corresponds to a table name, typically returned by a constant found in ConfigData
	 * @return
	 */
	protected abstract String getTableName();
	
	/**
	 * A unique id (index) is required for implementing generic create / update / delete methods 
	 * @return
	 */
	public abstract int getId();
	/**
	 * returns the unique id from the model 
	 * @return
	 */
	public abstract void setId(int id);

	/**
	 * list of observers that require notification (for MVC, see GoF Observer Design Pattern)
	 */
	protected ArrayList<Observer> observers = new ArrayList<Observer>(); 
	/**
	 * Attach an observer to this model
	 */
	public void addObserver( Observer o ) 
	{
        observers.add( o );
	}
	/**
	 * Detach observer from this model
	 */
	public void removeObserver( Observer o ) 
	{
        observers.remove( o );
	}
	/**
	 * loop through and notify each observer
	 */
	protected void notifyObservers() 
	{
      Iterator i = observers.iterator();
      while( i.hasNext() ) 
      {
            Observer o = ( Observer ) i.next();
            o.update( this );
      }
	}
	/**
	 * Create a row in the database, also updates the model with the new id and persists it via another UPDATE
	 */
	public int create() throws SQLException    
	{
		GetRow gr = new GetRow();
		try {
			int row = gr.findIntById(this.getId(), getTableName(), "id");
		} catch (NotFoundException e) {

			InsertRow ir = new InsertRow();
			int newId = ir.execute(getSqlReadyFields(), getTableName());
			System.out.println(String.format("old id: %d",this.getId()));
			this.setId(newId);
			UpdateRow ur = new UpdateRow();
			ur.execute(this.getId(), getSqlReadyFields(), getTableName());
			System.out.println(String.format("new id: %d",this.getId()));
			return newId;
		}
		UpdateRow ur = new UpdateRow();
		ur.execute(this.getId(), getSqlReadyFields(), getTableName());
		System.out.println(String.format("already there... saving: %d",this.getId()));
		return this.getId();
	}

	/**
	 * Delete the model's corresponding record in the database
	 */
	public boolean delete() throws SQLException {
		DeleteRow dr = new DeleteRow();
		return dr.execute(this.getId() , getTableName());
	}
	/**
	 * Persist changes to the model via an UPDATE statement
	 */
	public int update() throws SQLException {
		UpdateRow dr = new UpdateRow();
		return dr.execute(this.getId(), getSqlReadyFields(), getTableName());
	}
}
